
import { AttachedPickedInfo, ESJVector2DArray, ESJVector3D } from "earthsdk2s";
import { UeCloudViewerBase } from "./UeCloudViewerBase";
import { ESFlyToParam, NavigationModeCallFuncParam, UeFuncsType, UePickedInfo } from "./UeFuncsType";

const flyToCallFunc = async (viewer: UeCloudViewerBase, id?: string, duration?: number, flyToParam?: ESFlyToParam, position?: [number, number, number]) => {
    const res = await viewer.callUeFunc<UeFuncsType['flyTo']['result']>({
        f: 'flyTo',
        p: { id, duration, flyToParam, position }
    })
    if (res.error) {
        console.error(res.error);
        return undefined;
    }
    return res.re;
}
const destroyCallFunc = (viewer: UeCloudViewerBase, id: string) => {
    viewer.callUeFunc({ f: 'destroy', p: { id } });
}

const calcFlyToParamCallFunc = (viewer: UeCloudViewerBase, id: string) => {
    viewer.callUeFunc<UeFuncsType['calcFlyToParam']['result']>({
        f: 'calcFlyToParam',
        p: { id }
    }).then(res => {
        if (res.error) {
            console.error(`calcFlyToParam:`, res.error)
        }
    }).catch(err => {
        console.error(`calcFlyToParam:`, err)
    })
}
const refreshTilesetCallFunc = (viewer: UeCloudViewerBase, id: string) => {
    viewer.callUeFunc<UeFuncsType['refreshTileset']['result']>({
        f: 'refreshTileset',
        p: { id }
    }).then(res => {
        if (res.error) {
            console.error(`refreshTileset:`, res.error)
        }
    }).catch(err => {
        console.error(`refreshTileset:`, err)
    })
}
const flyInCallFunc = async (viewer: UeCloudViewerBase, id?: string, position?: [number, number, number], rotation?: [number, number, number], duration?: number) => {
    const res = await viewer.callUeFunc<UeFuncsType['flyIn']['result']>({
        f: 'flyIn',
        p: { id, position, rotation, duration }
    })
    if (res.error) {
        console.error(res.error);
        return undefined;
    }
    return res.re;
}
const flyInDefaultCameraCallFunc = async (viewer: UeCloudViewerBase, Duration?: number) => {
    if (!viewer) {
        console.warn('DefaultCameraFlyIn: viewer is undefined')
        return;
    }
    const res = await viewer.callUeFunc<UeFuncsType['DefaultCameraFlyIn']['result']>({
        f: 'DefaultCameraFlyIn',
        p: { Duration: Duration ?? 1 }
    })
    if (res.error) {
        console.error(`DefaultCameraFlyIn:`, res.error)
        return undefined;
    }
    return res;
}
const startVoiceCallFunc = async (viewer: UeCloudViewerBase) => {
    if (!viewer) {
        console.warn('StartVoice:viewer is undefined');
        return;
    }
    const res = await viewer.callUeFunc<UeFuncsType['StartVoice']['result']>({
        f: 'StartVoice',
        p: {}
    })
    if (res.error) {
        console.error(`StartVoice:`, res.error);
        return undefined;
    }
    return res;
}
const stopVoiceCallFunc = async (viewer: UeCloudViewerBase) => {
    if (!viewer) {
        console.warn('StopVoice:viewer is undefined');
        return;
    }
    const res = await viewer.callUeFunc<UeFuncsType['StopVoice']['result']>({
        f: 'StopVoice',
        p: {}
    })
    if (res.error) {
        console.error(`StopVoice:`, res.error);
        return undefined;
    }
    return res;
}
const generateMemReportCallFunc = async (viewer: UeCloudViewerBase) => {
    if (!viewer) {
        console.warn('generateMemReport:viewer is undefined');
        return;
    }
    const res = await viewer.callUeFunc<UeFuncsType['GenerateMemReport']['result']>({
        f: 'GenerateMemReport',
        p: {}
    })
    if (res.error) {
        console.error(`generateMemReport:`, res.error);
        return undefined;
    }
    return res;
}
const resetWithCurrentCameraCallFunc = (viewer: UeCloudViewerBase, id: string) => {
    viewer.callUeFunc<UeFuncsType['resetWithCurrentCamera']['result']>({
        f: 'resetWithCurrentCamera',
        p: { id }
    }).then(res => {
        if (res.error) {
            console.error(`resetWithCurrentCamera:`, res.error)
        }
    }).catch(err => {
        console.error(`resetWithCurrentCamera:`, err)
    })
}
const smoothMoveWithRotationCallFunc = (viewer: UeCloudViewerBase, id: string, Destination: [number, number, number], NewRotation: [number, number, number], Time: number) => {
    viewer.callUeFunc<UeFuncsType['smoothMoveWithRotation']['result']>({
        f: 'smoothMoveWithRotation',
        p: {
            id,
            Destination,
            NewRotation,
            Time
        }
    }).then(res => {
        if (res.error) {
            console.error(`smoothMoveWithRotation:`, res.error)
        }
    }).catch(err => {
        console.error(`smoothMoveWithRotation:`, err)
    })
}
const smoothMoveOnGroundCallFunc = (viewer: UeCloudViewerBase, id: string, Lon: number, Lat: number, Ground: string, Time: number) => {
    viewer.callUeFunc<UeFuncsType['smoothMoveOnGround']['result']>({
        f: 'smoothMoveOnGround',
        p: { id, Lon, Lat, Ground, Time }
    }).then(res => {
        if (res.error) {
            console.error(`smoothMoveOnGround:`, res.error)
        }
    }).catch(err => {
        console.error(`smoothMoveOnGround:`, err)
    })
}
const smoothMoveWithRotationOnGroundCallFunc = (viewer: UeCloudViewerBase, id: string, NewRotation: [number, number, number], Lon: number, Lat: number, Time: number, Ground: string) => {
    viewer.callUeFunc<UeFuncsType['smoothMoveWithRotationOnGround']['result']>({
        f: 'smoothMoveWithRotationOnGround',
        p: {
            id,
            NewRotation, Lon, Lat, Time, Ground
        }
    }).then(res => {
        if (res.error) {
            console.error(`smoothMoveWithRotationOnGround:`, res.error)
        }
    }).catch(err => {
        console.error(`smoothMoveWithRotationOnGround:`, err)
    })
}
const HighlightFeatureCallFunc = (viewer: UeCloudViewerBase, id: string, HlId: string) => {
    viewer.callUeFunc<UeFuncsType['HighlightFeature']['result']>({
        f: 'HighlightFeature',
        p: { id, HlId }
    }).then(res => {
        if (res.error) {
            console.error(`HighlightFeature:`, res.error)
        }
    }).catch(err => {
        console.error(`HighlightFeature:`, err)
    })
}
const HighlightFeatureAndFlyToCallFunc = (viewer: UeCloudViewerBase, id: string, HlId: string, Duration: number) => {
    viewer.callUeFunc<UeFuncsType['HighlightFeatureAndFlyTo']['result']>({
        f: 'HighlightFeatureAndFlyTo',
        p: { id, HlId, Duration }
    }).then(res => {
        if (res.error) {
            console.error(`HighlightFeatureAndFlyTo:`, res.error)
        }
    }).catch(err => {
        console.error(`HighlightFeatureAndFlyTo:`, err)
    })
}
const SetLayerVisibleCallFunc = (viewer: UeCloudViewerBase, id: string, LayerJson: string) => {
    viewer.callUeFunc<UeFuncsType['SetLayerVisible']['result']>({
        f: 'SetLayerVisible',
        p: { id, LayerJson }
    }).then(res => {
        if (res.error) {
            console.error(`SetLayerVisible:`, res.error)
        }
    }).catch(err => {
        console.error(`SetLayerVisible:`, err)
    })
}
const SetLayerColorCallFunc = (viewer: UeCloudViewerBase, id: string, LayerJson: string) => {
    viewer.callUeFunc<UeFuncsType['SetLayerColor']['result']>({
        f: 'SetLayerColor',
        p: { id, LayerJson }
    }).then(res => {
        if (res.error) {
            console.error(`SetLayerColor:`, res.error)
        }
    }).catch(err => {
        console.error(`SetLayerColor:`, err)
    })
}
const smoothMoveCallFunc = (viewer: UeCloudViewerBase, id: string, Destination: [number, number, number], Time: number) => {
    viewer.callUeFunc<UeFuncsType['smoothMove']['result']>({
        f: 'smoothMove',
        p: {
            id,
            Destination,
            Time
        }
    }).then(res => {
        if (res.error) {
            console.error(`smoothMove:`, res.error)
        }
    }).catch(err => {
        console.error(`smoothMove:`, err)
    })
}
const callFunctionCallFunc = (viewer: UeCloudViewerBase, id: string, fn: string, p: { [k: string]: any; }) => {
    viewer.callUeFunc<UeFuncsType['callFunction']['result']>({
        f: 'callFunction',
        p: {
            id,
            fn, p
        }
    }).then(res => {
        if (res.error) {
            console.error(`callFunction:`, res.error);
            console.error(`id: ${id} fn: ${fn} param: ${p}`);
        }
    }).catch(err => {
        console.error(`callFunction:`, err)
        console.error(`id: ${id} fn: ${fn} param: ${p}`);
    })
}
const setNodePositionCallFunc = (viewer: UeCloudViewerBase, id: string, NodeName: string, NodePosition: [number, number, number]) => {
    viewer.callUeFunc<UeFuncsType['SetNodePosition']['result']>({
        f: 'SetNodePosition',
        p: {
            id, NodeName, NodePosition
        }
    }).then(res => {
        if (res.error) {
            console.error(`SetNodePosition:`, res.error);
        }
    }).catch(err => {
        console.error(`SetNodePosition:`, err)
    })

}
const setNodeRotationCallFunc = (viewer: UeCloudViewerBase, id: string, NodeName: string, NodeRotation: [number, number, number]) => {
    viewer.callUeFunc<UeFuncsType['SetNodeRotation']['result']>({
        f: 'SetNodeRotation',
        p: {
            id, NodeName, NodeRotation
        }
    }).then(res => {
        if (res.error) {
            console.error(`SetNodeRotation:`, res.error);
        }
    }).catch(err => {
        console.error(`SetNodeRotation:`, err)
    })

}
const setNodeScaleCallFunc = (viewer: UeCloudViewerBase, id: string, NodeName: string, NodeScale: [number, number, number]) => {
    viewer.callUeFunc<UeFuncsType['SetNodeScale']['result']>({
        f: 'SetNodeScale',
        p: {
            id, NodeName, NodeScale
        }
    }).then(res => {
        if (res.error) {
            console.error(`SetNodeScale:`, res.error);
        }
    }).catch(err => {
        console.error(`SetNodeScale:`, err)
    })

}
const changeNavigationModeCallFunc = async (viewer: UeCloudViewerBase, parms: NavigationModeCallFuncParam) => {
    const res = await viewer.callUeFunc<UeFuncsType['ChangeNavigationMode']['result']>({
        f: 'ChangeNavigationMode',
        p: parms
    })
    if (res.error) {
        console.error(`ChangeNavigationMode:`, res.error)
        return undefined;
    }
    return res;
}
const setGlobalPropertyCallFunc = async (viewer: UeCloudViewerBase, params: { [k: string]: any; }) => {
    const res = await viewer.callUeFunc<UeFuncsType['setGlobalProperty']['result']>({
        f: 'setGlobalProperty',
        p: params
    })
    if (res.error) {
        console.error(`setGlobalProperty:`, res.error)
        return undefined;
    }
    return res;
}
const quitCallFunc = async (viewer: UeCloudViewerBase) => {
    const res = await viewer.callUeFunc<UeFuncsType['Quit']['result']>({
        f: 'Quit',
        p: undefined
    })
    if (res.error) {
        console.error(`Quit:`, res.error)
        return undefined;
    }
    return res;
}

const pickCallFunc = async (viewer: UeCloudViewerBase, screenPosition_?: [number, number], attachedInfo?: any, parentInfo_?: boolean) => {
    const res = await viewer.callUeFunc<UeFuncsType['pick']['result']>({
        f: 'pick',
        p: { screenPosition: screenPosition_, parentInfo: parentInfo_ }
    })
    if (!res.re && (res.error || res.error == "")) {
        console.error(`pick:`, res.error == "" ? "未获取到结果" : res.error);
        return undefined;
    }
    const pickedInfo = new UePickedInfo(res.re, new AttachedPickedInfo(attachedInfo), res.re.features);
    return pickedInfo;
}

const pickPositionCallFunc = async (viewer: UeCloudViewerBase, screenPosition_?: [number, number]) => {
    const res = await viewer.callUeFunc<UeFuncsType['pickPosition']['result']>({
        f: 'pickPosition',
        p: { screenPosition: screenPosition_ }
    })
    if (!res.re && (res.error || res.error == "")) {
        console.error(`pickPosition`, res.error == "" ? "未获取到结果" : res.error);
        return undefined;
    }
    const { position } = res.re;
    return position;
}

export const getHeightByLonLatCallFunc = async (viewer: UeCloudViewerBase, Lon: number, Lat: number, Channel: string = "ECC_Visibility") => {
    const res = await viewer.callUeFunc<UeFuncsType['GetHeightByLonLat']['result']>({
        f: 'GetHeightByLonLat',
        p: { Lon, Lat, Channel }
    })
    if (res.error) {
        console.warn(`GetHeightByLonLat:${res.error}`);
        return undefined;
    }
    return res.re;
}
export const getHeightByLonLatsCallFunc = async (viewer: UeCloudViewerBase, LonLats: ESJVector2DArray, Channel: string = "ECC_Visibility") => {
    const res = await viewer.callUeFunc<UeFuncsType['GetHeightsByLonLats']['result']>({
        f: 'GetHeightsByLonLats',
        p: { LonLats, Channel }
    })
    if (res.error) {
        console.warn(`GetHeightsByLonLats:${res.error}`);
        return undefined;
    }
    if (res.re.heights.includes(null)) {
        console.warn('注意! GetHeightsByLonLats: 存在高度为null的点. there are points with a height of null');
    }
    try {
        return res.re.heights;
    } catch (error) {
        return undefined;
    }
}

export const captureCallFunc = async (viewer: UeCloudViewerBase, resx: number = 64, resy: number = 64) => {
    const res = await viewer.callUeFunc<UeFuncsType['capture']['result']>({
        f: 'capture',
        p: { resx, resy }
    });
    if (res.error) {
        console.warn(res.error);
        return undefined;
    }
    return res.re.image;
}


export const getLonLatAltToScreenPositionCallFunc = async (viewer: UeCloudViewerBase, position: ESJVector3D) => {
    const res = await viewer.callUeFunc<UeFuncsType['LonLatAltToScreenPosition']['result']>({
        f: 'LonLatAltToScreenPosition',
        p: { LonLatAlt: position }
    });
    if (res.error) {
        console.warn(res.error);
    }
    return res.re
}



export {
    generateMemReportCallFunc, startVoiceCallFunc, pickCallFunc, stopVoiceCallFunc, HighlightFeatureAndFlyToCallFunc,
    HighlightFeatureCallFunc, SetLayerColorCallFunc, SetLayerVisibleCallFunc, calcFlyToParamCallFunc,
    callFunctionCallFunc, changeNavigationModeCallFunc, destroyCallFunc, flyInCallFunc, flyInDefaultCameraCallFunc,
    flyToCallFunc, pickPositionCallFunc, quitCallFunc, refreshTilesetCallFunc, resetWithCurrentCameraCallFunc,
    setGlobalPropertyCallFunc, setNodePositionCallFunc, setNodeRotationCallFunc, setNodeScaleCallFunc, smoothMoveCallFunc,
    smoothMoveOnGroundCallFunc, smoothMoveWithRotationCallFunc, smoothMoveWithRotationOnGroundCallFunc
};

